#!/usr/bin/python
'''The Account Manager handles the UI for creating, editing, and deleting accounts. It shows
the status of each account (connected/disconnected).
When an account is connected, the account_manager creates a new service UI. When that service UI
is closed, the status is reflected on the account icon.

Account properties are handled by the account_props class.
'''
ident = '$Id: account_manager.py 146 2006-08-23 01:42:44Z trevor $'
import wx, sys
from wx.lib.mixins.listctrl 	import ColumnSorterMixin
import common
import icon_manager
import images
import webbrowser
import rex
import account_ui
import about
import tracer
import time
import os
from xml.dom	import minidom
import wx.lib.hyperlink as hl

# Button IDs
ID_CREATE_ACCOUNT = 101
ID_EDIT_ACCOUNT   = 102
ID_DELETE_ACCOUNT = 103
ID_CONNECT_ACCOUNT= 104
ID_FRAME_TIMER    = 120
ID_HIDE_TIMER	  = 121

IDM_CREATE		= 201
IDM_CONNECT		= 202
IDM_EDIT		= 203
IDM_DELETE		= 204
IDM_EXIT		= 205
IDM_ABOUT		= 206
IDM_SUPPORT		= 208
IDM_TRACE		= 209
IDM_FONTS		= 210
IDM_IMPORT		= 211

#################################
class starterWindow(wx.Panel):
	def __init__(self, parent, id=-1, size=wx.DefaultSize, bgcolor=None):
		wx.Panel.__init__( self, parent )
		self.parent = parent
		self.grid = wx.FlexGridSizer( 7, 2, 20, 20 )
		self.username  = wx.TextCtrl(self, -1, '')
		self.password = wx.TextCtrl(self, -1, '',style=wx.TE_PASSWORD)
		self.button = wx.Button(self, IDM_IMPORT, 'Import')
		self.button.Bind(wx.EVT_BUTTON, self.OnButton)
		self.thx = wx.Button(self, IDM_IMPORT, 'No thanks')
		self.thx.Bind(wx.EVT_BUTTON, self.OnThx)
		self.devlink = hl.HyperLinkCtrl(self, wx.ID_ANY, "Get A New Etelos Developer Account", URL="http://www.etelos.com/devaccount/")
		Msg1 = """
Welcome to Etelos OpenDev!

If you have an Etelos Support or Etelos Store username
and password, please login to import your server accounts.

		"""
		Msg2 = """
Or you can click the link below to 
		"""
		inputs = [ 
			( (0,0) ),
			(wx.StaticText( self, -1, Msg1 , style=wx.ALIGN_LEFT ), 0, wx.EXPAND),
			( wx.StaticText( self, -1, "Username", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
			( self.username, 1, wx.EXPAND | wx.GROW ),
			( wx.StaticText( self, -1, "Password", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
			( self.password, 1, wx.EXPAND | wx.GROW ),
			((0,0)),
			( self.button,1,wx.EXPAND),
			((0,0)),
			( wx.StaticText( self, -1, Msg2 , style=wx.ALIGN_LEFT ), 0, wx.EXPAND ),
			((0,0)),
			(self.devlink,1,wx.EXPAND),
			((0,0)),
			( self.thx,1,wx.EXPAND) ]
		self.grid.AddMany( inputs )
		self.grid.AddGrowableCol( 1 )
		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( self.grid, 1, wx.EXPAND|wx.NORTH|wx.SOUTH|wx.EAST|wx.WEST,50 )
		self.SetSizer(self.sizer)

	def OnButton(self,event):
		username = self.username.GetValue()
		password = self.password.GetValue()
		common.dprint( "Got username: %s password: %s " % (username,password))
		busy = wx.BusyInfo("One moment please, downloading account information...")
		wx.Yield()
		time.sleep(1)
		vars = [( u'username', username ),
				( u'password', password ),
				( u'rtalk', u'71' ),]
		result = False
		doc = ''
		try:
			form= common.http_post_form( 'www.etelos.com', '/developer/accounts.esp', vars )
			common.dprint("Sending request");
			doc	= form.submit()
			common.dprint("Got result: %s" % doc);
			doc = doc.strip()
			if len( doc ) < 10:
				common.dprint( "Download failed: ", doc )
			else:
				result = True
		except:
			common.show_error("Failed to download accounts information")
		del busy
		# got accounts
		xmlstring = common.uni2str( doc )
		pdom 	= minidom.parseString( xmlstring )
		for anode in pdom.getElementsByTagName("account"):
			account_name = anode.getAttribute('name')
			account_server = anode.getAttribute('server')
			account_username = anode.getAttribute('username')
			account_password = anode.getAttribute('password')
			account_projectdir = os.path.join(os.path.expanduser('~'),'opendev',account_name)
			account = rex.accounts.create_account( account_name, account_server, account_username, account_password )
		# We are done, lets close up
		self.parent.GetParent().refreshAccountsList()
		self.OnThx()
		
	def OnThx(self,event=None):
		self.parent.GetParent().OnImport(None)
	
	def OnNewAccount(self,event=None):
		webbrowser.open("http://support.etelos.com")
#################################
class account_manager( wx.Frame ):
	'''The Account Manager UI Frame'''
	def __init__( self, parent, id, title ):
		window_pos	= ( common.account_manager_x, common.account_manager_y )
		window_size	= ( common.account_manager_w, common.account_manager_h )
		wx.Frame.__init__( self, parent, id, title, pos=window_pos, size=window_size,
			style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE )
		common.metalic(self)
		self.inStarterMode = False
		self.currentItem= None
		self.services 	= {}
		self.sort_asc	= True
		self.create_menu_items()
		# Connect a timer to this frame
		self.timer = wx.Timer( self, ID_FRAME_TIMER )
		self.hide_me_timer = wx.Timer( self, ID_HIDE_TIMER )
		self.Bind( wx.EVT_TIMER, self.OnTimer )
		# Create an image list
		self.il = wx.ImageList(16, 16)
		# Load our images
		self.disconnected_icon 	= self.il.Add( images.getDisconnectedBitmap() )
		self.connecting_icon 	= self.il.Add( images.getConnectingBitmap() )
		self.connected_icon 	= self.il.Add( images.getConnectedBitmap() )
		self.failed_icon 		= self.il.Add( images.getFailedBitmap() )		
		self.splitter = wx.SplitterWindow( self, -1 )
		# Create the list control and set it's image list
		tID = wx.NewId()
		self.list = wx.ListCtrl(self.splitter, tID, style=wx.LC_REPORT|wx.LC_SINGLE_SEL )#|wx.LC_VRULES|wx.LC_HRULES)
		self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
		# Create the column headers
		info = wx.ListItem()
		info.m_mask = wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_image = -1
		info.m_text = "Account"
		self.list.InsertColumnInfo(0, info)
		info.m_text = "Status"
		self.list.InsertColumnInfo(1, info)
		info.m_text = "Server"
		self.list.InsertColumnInfo(2, info)
		# Set the events
		self.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.OnActivateAccount, id=tID )
		self.Bind( wx.EVT_LIST_COL_CLICK, self.OnColClick, id=tID )
		self.Bind( wx.EVT_CLOSE, self.OnClose )
		self.list.Bind( wx.EVT_RIGHT_DOWN, self.OnAccountRightClick )
		# Create a status bar
		self.CreateStatusBar()
		# Now sizeup the whole set
		# the html window
		self.starter = starterWindow(self.splitter)
		self.splitter.SplitHorizontally( self.list, self.starter )
		self.splitter.Unsplit(self.starter)
		self.list.Show()
		self.list.Refresh()
		self.starter.Show(False)
		#self.starter.Refresh()
		self.splitter.Show()
		self.splitter.Refresh()
		# Set the frame icon
		icon = icon_manager.get_icon( "ESM" )
		self.SetIcon( icon )
		self.SetStatusText( "Ready" )
		# Sort the accounts by name
		self.clicked_column = 0
		self.list.SortItems( self.OnSort )
				
	def create_menu_items( self ):
		# Create the menu bar
		menubar = wx.MenuBar()
		self.menubar = menubar
		# The accounts menu
		menu = wx.Menu()
		menu.Append( IDM_CONNECT,"Co&nnect"," Connect to the selected service account" )
		menu.AppendSeparator()
		self.create_mi = wx.MenuItem( menu, IDM_CREATE, "&Create", " Create a new service account" )
		menu.AppendItem( self.create_mi )
		self.import_mi = wx.MenuItem( menu, IDM_IMPORT, "&Import", " Import accounts from your Etelos Developer account" )
		menu.AppendItem( self.import_mi )
		menu.Append( IDM_EDIT,   "&Edit",   " Edit the selected service account" )
		self.delete_mi = wx.MenuItem( menu, IDM_DELETE, "&Delete", " Delete the selected service account" )
		menu.AppendItem( self.delete_mi )
		menu.AppendSeparator()
		menu.Append( IDM_EXIT, "E&xit", " Exit the Etelos Services Manager" )
		self.Bind( wx.EVT_MENU, self.OnCreateAccount, id=IDM_CREATE )
		self.Bind( wx.EVT_MENU, self.OnImport, id=IDM_IMPORT )
		self.Bind( wx.EVT_MENU, self.OnActivateAccount, id=IDM_CONNECT )
		self.Bind( wx.EVT_MENU, self.OnEditAccount, id=IDM_EDIT	)
		self.Bind( wx.EVT_MENU, self.OnDeleteAccount, id=IDM_DELETE )
		self.Bind( wx.EVT_MENU, self.OnClose, id=IDM_EXIT )
		menubar.Append( menu, "&Account" )
		self.accounts_menu = menu

		# The frm menu
		menu = wx.Menu()
		menu.Append( IDM_SUPPORT, 	 "&Support"," Connect to Etelos support services" )
		menu.Append( IDM_TRACE, 	 "&Open Tracer", " Open the EDE Trace Utility" )
		menu.Append( IDM_FONTS, 	 "Set Editor &Font", " Set the default editor font" )
		menu.AppendSeparator()
		menu.Append( IDM_ABOUT, 	 "&About EDE", " About EDE" )
		self.Bind( wx.EVT_MENU, self.OnAbout,		id=IDM_ABOUT )
		self.Bind( wx.EVT_MENU, self.OnTrace,		id=IDM_TRACE )
		self.Bind( wx.EVT_MENU, self.OnSelectFont,	id=IDM_FONTS )
		self.Bind( wx.EVT_MENU, self.OnSupport,		id=IDM_SUPPORT )
		menubar.Append( menu, "&Help" )
		# All done
		self.SetMenuBar( menubar )

	def OnImport(self,event=None):
		if not self.inStarterMode:
			self.inStarterMode = True
			self.splitter.SplitHorizontally(self.starter,self.list,300)
			self.splitter.Unsplit(self.list)
			self.list.Show(False)
			self.starter.Show(True)
		else:
			self.inStarterMode = False
			self.splitter.SplitHorizontally(self.list,self.starter,300)
			self.splitter.Unsplit(self.starter)
			self.starter.Show(False)
			self.list.Show(True)

	def OnSelectFont( self, event ):
		data = wx.FontData()
		data.EnableEffects( True )
		font = wx.Font( int( common.default_font_size ), wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, common.default_font_family )
		data.SetInitialFont( font )
		dlg = wx.FontDialog(self, data)
		if dlg.ShowModal() == wx.ID_OK:
			data = dlg.GetFontData()
			font = data.GetChosenFont()
			try:
				common.default_font_family = font.GetFaceName()
				common.default_font_size = int( font.GetPointSize() )
			except:
				pass
			rex.accounts.save_conf_file()
		dlg.Destroy()

	def OnClose( self, event ):
		for name,account in rex.accounts.accounts.items():
			if account.connected and account.window:
				common.dprint("Disconnecting this account")
				account.window.OnDisconnect( None )
		self.Destroy()

	def OnAbout( self, event ):
		dlg = about.AboutDialog()
		dlg.ShowModal()
		dlg.Destroy()
		del dlg

	def OnSupport( self, event ):
		webbrowser.open("http://support.etelos.com")

	def OnTrace( self, event ):
		try:
			if common.tracer is None:
				common.tracer	= tracer.tracer( self )
				common.tracer.Show()
			else:
				common.tracer.Raise()
		except:
			common.show_error("Failed to open the tracer")

	def Show( self, show_it=True ):
		# Load the accounts
		rex.accounts.load_accounts()
		# Add the accounts
		self.reload_accounts()
		self.resize_columns()
		self.list.SortItems( self.OnSort )
		wx.Frame.Show( self, show_it )
		if common.firstrun:
			self.OnImport(None)
			common.firstrun = False

	def get_icon_id_from_kind( self, kind ):
		ticon = 0
		if kind == "Newsletter":
			ticon = self.newsletter_icon
		elif kind == "Web":
			ticon = self.web_icon
		elif kind == "Email":
			ticon = self.email_icon
		elif kind == "Survey":
			ticon = self.survey_icon
		elif kind == "Referral":
			ticon = self.referral_icon
		return ticon
	def refreshAccountsList(self,event=None):
		self.reload_accounts()
		self.resize_columns()
	def reload_accounts( self ):
		'''Used internally to reload the accounts list'''
		self.list.DeleteAllItems()
		for account_id in rex.accounts.accounts:
			account = rex.accounts.accounts[ account_id ]
			# For now, hardcode Web
			index = self.list.InsertImageStringItem( sys.maxint, account.name, self.disconnected_icon )
			self.list.SetStringItem( index, 1, "Ready" )
			self.list.SetStringItem( index, 2, account.server )
			self.list.SetItemData( index, account_id )
		self.currentItem = None

	def resize_columns( self ):
		'''Used internally to recalculate the column sizes'''
		# Set the column header sizes
		self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
		self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)

	def OnAccountRightClick( self, event ):
		try:
			self.x = event.GetX()
			self.y = event.GetY()
			item, flags = self.list.HitTest((self.x, self.y))
			if flags & wx.LIST_HITTEST_ONITEM:
				self.list.Select(item)
		except:
			pass
		self.PopupMenu( self.accounts_menu, wx.Point( event.m_x, event.m_y + 10) )

	def OnItemActivated(self, event):
		'''Sets the internal currentItem variable to the currently selected account list item'''
		self.currentItem = event.m_itemIndex

	def OnCreateAccount( self, event ):
		'''Handles requests to create a new account'''
		if self.currentItem is None:
			item = None
		else:
			item = self.list.GetItem( self.currentItem )
		# Create an account properties dialog
		dlg = account_props( self, None )
		common.metalic( dlg )
		res = dlg.ShowModal()
		if res != wx.ID_OK:
			dlg.Destroy()
			dlg = None
			return
		# We are in business
		name, server, username, password = (
				dlg.name_control.GetValue(),
				dlg.server_control.GetValue(),
				dlg.username_control.GetValue(),
				dlg.password_control.GetValue() )
		account = rex.accounts.create_account( name, server, username, password )
		if account is None:
			return
		index = self.list.InsertImageStringItem( sys.maxint, account.name, self.disconnected_icon )
		self.list.SetStringItem( index, 1, "Ready" )
		self.list.SetStringItem( index, 2, account.server )
		self.list.SetItemData( index, account.id )
		self.resize_columns()

	def OnEditAccount( self, event ):
		'''Handles requests to edit the selected account'''
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		self.currentItem = sel[0]
		item = self.list.GetItem( self.currentItem )
		ai = item.GetData()
		account = rex.accounts.accounts[ ai ]
		oldname = account.name
		if account.connected:
			dlg = wx.MessageDialog( self, "This account is currently connected", "Edit Account", wx.OK )
			icon = icon_manager.get_icon( "ESM" )
			dlg.SetIcon( icon )
			dlg.ShowModal()
			dlg.Destroy()
			dlg = None
			return
		# Create an account properties dialog
		dlg = account_props( self, account )
		common.metalic( dlg )
		res = dlg.ShowModal()
		if res != wx.ID_OK:
			dlg.Destroy()
			dlg = None
			return
		# We are in business
		#full_url = "%s/soap/%s.esp" % ( url, type.lower() )
		account.name, \
		account.server, \
		account.username, \
		account.password  = (
		dlg.name_control.GetValue(),
		dlg.server_control.GetValue(),
		dlg.username_control.GetValue(),
		dlg.password_control.GetValue() )
		if( oldname != account.name ):
			account.save( oldname )
		else:
			account.save()
		#~ ticon = self.get_icon_id_from_kind( account.module )
		item.SetText( account.name )
		#~ item.SetImage( ticon )
		#~ self.list.SetStringItem( self.currentItem , 2, account.module )
		self.list.SetStringItem( self.currentItem , 2, account.server )
		self.list.SetItem( item )
		self.resize_columns()

	def OnDeleteAccount( self, event ):
		'''Handles requests to delete the selected account'''
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		self.currentItem = sel[0]
		item = self.list.GetItem( self.currentItem )
		ai = item.GetData()
		account = rex.accounts.accounts[ ai ]
		if account.connected:
			dlg = wx.MessageDialog( self, "This account is currently connected", "Delete Account",
									wx.OK )
			icon = icon_manager.get_icon( "ESM" )
			dlg.SetIcon( icon )
			dlg.ShowModal()
			dlg.Destroy()
			dlg = None
			return
		# Confirm
		dlg = wx.MessageDialog( self, "Are you sure you want to delete this account?\n\n    %s" % \
							   account.name, "Confirm Delete", wx.YES_NO )
		icon = icon_manager.get_icon( "ESM" )
		dlg.SetIcon( icon )
		if dlg.ShowModal() != wx.ID_YES:
			dlg.Destroy()
			dlg = None
			return
		rex.accounts.delete_account( account.id )
		self.list.DeleteItem( item.GetId() )
		self.resize_columns()

	def OnActivateAccount( self, event ):
		'''Handles requests to connect an account'''
		# Do we have a selected account?
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		self.currentItem = sel[0]
		if self.currentItem is None: return
		# Get the item
		item = self.list.GetItem( self.currentItem )
		# Get the account index and attempt a connection
		aid  = item.GetData()
		account = rex.accounts.accounts[ aid ]
		if account.window is not None:
			account.window.Raise()
			return
		self.SetStatusText( "Connecting ..." )
		common.set_busy_info( "Connecting to %s..." % account.server )
		self.list.SetStringItem( self.currentItem, 0, account.name, self.connecting_icon )
		self.list.SetStringItem( self.currentItem, 1, "Trying..." )
		self.resize_columns()
		wx.Yield()
		cur = wx.BusyCursor()
		wx.Yield()
		try:
			account.connect()
		except:
			common.show_error('')
			print "Failed to connect"
		del cur
		common.clear_busy_info()
		# Are we connected?
		if not account.connected:
			self.list.SetStringItem( self.currentItem, 0, account.name, self.failed_icon )
			self.list.SetStringItem( self.currentItem, 1, "Failed" )
			self.resize_columns()
			wx.Yield()
			self.SetStatusText( "Failed to connect" )
			return
		else:
			self.list.SetStringItem( self.currentItem, 0, account.name, self.connected_icon )
			self.list.SetStringItem( self.currentItem, 1, "Connected" )
			self.resize_columns()
			wx.Yield()
			
		# Check to make sure the server supports the license extentions
		try:
			xmlstring = account.execute2( 'base', "get_licenses")
		except:
			dlg = wx.MessageDialog( None, "The Server you are trying to connect to does not support the License extensions. Please use an older version of the EDE to connect to this server.",
									"EAS Server Error",
									wx.OK | wx.ICON_ERROR)
			dlg.ShowModal()
			dlg.Destroy()

			self.list.SetStringItem( self.currentItem, 0, account.name, self.failed_icon )
			self.list.SetStringItem( self.currentItem, 1, "Failed" )
			self.resize_columns()
			wx.Yield()
			self.SetStatusText( "Failed to connect" )
			return
			
		account.window = account_ui.account_frame( self, account.name, account )
		self.hide_me_timer.Start( 500, 1 )
		account.window.Raise()
		#event.StopPropagation()
		
	def OnColClick( self, event ):
		'''Handles requests to sort the accounts list'''
		self.clicked_column = event.GetColumn()
		self.sort_asc = not self.sort_asc
		self.list.SortItems( self.OnSort )

	def OnColRightClick( self, event ):
		pass

	def OnSort( self, item1, item2 ):
		'''The sorting function'''
		account1 = rex.accounts.accounts[ item1 ]
		account2 = rex.accounts.accounts[ item2 ]

		ac1 = ( account1.name,
				account1.connected,
				account1.server )
		ac2 = ( account2.name,
				account2.connected,
				account2.server )
		if self.sort_asc:
			val = cmp( ac1[self.clicked_column].lower(), ac2[self.clicked_column].lower() )
		else:
			val = cmp( ac2[self.clicked_column].lower(), ac1[self.clicked_column].lower() )
		return val

	def OnTimer( self, event ):
		'''Resets the status bar text back to "Ready"'''
		timer_id = event.GetId()
		if timer_id == ID_FRAME_TIMER:
			self.SetStatusText( "Ready" )
		elif timer_id == ID_HIDE_TIMER:
			self.Iconize()

	def disconnect_account( self, aid ):
		if aid is 0: return 1
		# Get the item by the AID
		index = self.list.FindItemData( -1, aid )
		item = self.list.GetItem( index )
		account = rex.accounts.accounts[ aid ]
		# Confirm
		self.list.SetStringItem( index, 0, account.name, self.disconnected_icon )
		self.list.SetStringItem( index, 1, "Ready" )
		self.resize_columns()
		wx.Yield()
		# call save to save the window dimensions before it dies
		account.save()
		account.connected = False
		# remove the reference to the service frame
		account.window = None
		self.Raise()
		return True

	def set_account_loading( self, aid, progress = "Loading..." ):
		if aid is 0: return 1
		# Get the item by the AID
		index = self.list.FindItemData( -1, aid )
		self.list.SetStringItem( index, 1, progress )
		self.SetStatusText( progress )
		self.resize_columns()
		wx.Yield()

	def set_account_loaded( self, aid ):
		if aid is 0: return 1
		# Get the item by the AID
		index = self.list.FindItemData( -1, aid )
		self.list.SetStringItem( index, 1, "Connected" )
		self.resize_columns()
		wx.Yield()
		self.SetStatusText( "Connected" )
		self.timer.Start( 5000, 1 )


class account_props( wx.Dialog ):
	'''Provides the UI to manipulate an accounts properties'''
	def __init__( self, parent, account ):
		type_selection = 0
		if account is None:
			caption = "New Account Properties"
			name, server, username, password = ( "", "", "", "" )
		else:
			caption = "Account Properties"
			name, server, username, password = (
					account.name,
					account.server,
					account.username,
					account.password )

		wx.Dialog.__init__( self, parent, -1, caption,
						   wx.DefaultPosition, wx.Size( 450, 250 )  )
		# Create the input fields
		self.name_control = wx.TextCtrl( self, -1, name )
		self.server_control  = wx.TextCtrl( self, -1, server )
		self.username_control  = wx.TextCtrl( self, -1, username )
		self.password_control  = wx.TextCtrl( self, -1, password, style=wx.TE_PASSWORD )

		self.grid = wx.FlexGridSizer( 5, 2, 2, 2 )
		inputs = [ ( wx.StaticText( self, -1, "Name", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.name_control, 1, wx.EXPAND | wx.GROW ),
				   ( wx.StaticText( self, -1, "Server",  style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.server_control, 1, wx.EXPAND  | wx.GROW ),
				   ( wx.StaticText( self, -1, "",  style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( wx.StaticText( self, -1, "",  style=wx.ALIGN_RIGHT ), 1, wx.EXPAND  | wx.GROW ), # this used to be the secure checkbox.  The location is reserved for future use.
				   ( wx.StaticText( self, -1, "Username", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.username_control, 1, wx.EXPAND | wx.GROW ),
				   ( wx.StaticText( self, -1, "Password", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.password_control, 1, wx.EXPAND | wx.GROW ) ]
		self.grid.AddMany( inputs )
		self.grid.AddGrowableCol( 1 )
		# Add the buttons
		self.button_sizer = wx.BoxSizer( wx.HORIZONTAL )
		btn = wx.Button( self, wx.ID_OK, "&Save" )
		btn.SetDefault()
		self.button_sizer.Add( (0,0) , 0, 1 )
		self.button_sizer.Add( btn, 1, 0 )
		self.button_sizer.Add( (10,10), 1, 1 )
		btn = wx.Button( self, wx.ID_CANCEL, "&Cancel" )
		self.button_sizer.Add( btn, 1, 0 )
		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( self.grid, 1, wx.EXPAND | wx.NORTH | wx.SOUTH | wx.EAST | wx.WEST, 10 )
		self.sizer.Add( self.button_sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.SOUTH, 20 )
		self.SetSizer( self.sizer )
		self.SetAutoLayout( 1 )
		icon = icon_manager.get_icon( "ESM" )
		self.SetIcon( icon )
		# Windows needs this call
		self.Layout()
	def OnSelectDir(self,event):
		dlg = wx.DirDialog(self, "Choose a local project directory:",
		                          style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
		res = dlg.ShowModal()
		if res  == wx.ID_OK:
			self.projectdir_control.SetValue(dlg.GetPath())
		dlg.Destroy()
